#include "RenderTexture.h"

RenderTexture::RenderTexture(int res_x, int res_y, bool hasDepth /* = false */, int smoothtype,
							 int texturetype)
{
	this->hasDepth = hasDepth;
	this->res_x = res_x;
	this->res_y = res_y;
	this->textype = texturetype;

	GLenum internalformat = GL_RGBA16F_ARB;
	GLenum format = GL_RGBA;
	GLenum type = GL_HALF_FLOAT_ARB;

	glGenFramebuffersEXT(1, &sharedFBO);
	glGenTextures(1, &renderTexID);

	glBindTexture(texturetype, renderTexID);

	glTexImage2D(texturetype, 0, internalformat, res_x, res_y, 0, format, type, 0);// (set texture parameters here)
	//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);	
	glTexParameterf(texturetype, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameterf(texturetype, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameterf(texturetype, GL_TEXTURE_MAG_FILTER, smoothtype);
	glTexParameterf(texturetype, GL_TEXTURE_MIN_FILTER, smoothtype);

	if(hasDepth)
	{
		//glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sharedFBO); 
		glGenTextures(1, &depthTexID);
		glBindTexture(GL_TEXTURE_2D, depthTexID);
		glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, res_x, res_y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameterf( GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
	}

	startRender();
	glClearColor(0, 0, 0, 0.f);
	glClear(GL_COLOR_BUFFER_BIT);
	if (hasDepth)
	{
		glClearDepth(1.f);
		glClear(GL_DEPTH_BUFFER_BIT);
	}
	endRender();
}

RenderTexture::~RenderTexture()
{
	glDeleteFramebuffers(1, &sharedFBO);
	glDeleteTextures(1, &renderTexID);
	if (hasDepth)
		glDeleteTextures(1, &depthTexID);
}

IteratedRenderTexture::IteratedRenderTexture(int res_x, int res_y, bool hasDepth, int smoothtype, GLenum target,
											 GLenum internalformat, GLenum format, GLenum type, GLvoid* texels)
{
	this->hasDepth = hasDepth;
	this->res_x = res_x;
	this->res_y = res_y;
	this->target = target;

	glGenFramebuffersEXT(1, &sharedFBO);
	glGenTextures(1, &textureTexID);
	glGenTextures(1, &renderTexID);

	glBindTexture(target, textureTexID);

	glTexImage2D(target, 0, internalformat, res_x, res_y, 0, format, type, texels);// (set texture parameters here)
	glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameterf(target, GL_TEXTURE_MAG_FILTER, smoothtype);
	glTexParameterf(target, GL_TEXTURE_MIN_FILTER, smoothtype);

	glBindTexture(target, renderTexID);

	glTexImage2D(target, 0, internalformat, res_x, res_y, 0, format, type, 0);// (set texture parameters here)
	glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameterf(target, GL_TEXTURE_MAG_FILTER, smoothtype);
	glTexParameterf(target, GL_TEXTURE_MIN_FILTER, smoothtype);	

	if(hasDepth)
	{
		glGenTextures(1, &depthTexID);
		glBindTexture(GL_TEXTURE_2D, depthTexID);
		glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, res_x, res_y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameterf( GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
	}

	startRender();
	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT);
	if(hasDepth)
	{
		glClearDepth(1.0);
		glClear(GL_DEPTH_BUFFER_BIT);
	}
	endRender();

	//do once more to initialize the other texture
	startRender();
	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT);
	endRender();
}

IteratedRenderTexture::~IteratedRenderTexture()
{
	glDeleteFramebuffers(1, &sharedFBO);
	glDeleteTextures(1, &renderTexID);
	glDeleteTextures(1, &textureTexID);
	if (hasDepth)
		glDeleteTextures(1, &depthTexID);
}

void IteratedRenderTexture::reset()
{
	startRender();
	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT);	
	endRender();
	startRender();
	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT);	
	endRender();
}

MultiIteratedRenderTexture::MultiIteratedRenderTexture(int res_x, int res_y, int smoothtype,
													   int texturetype)
{
	nTexture = 3;
	textureId = new GLuint[nTexture];
	Idtex = 1;

	this->res_x = res_x;
	this->res_y = res_y;

	GLenum internalformat = GL_RGBA16F_ARB;
	GLenum format = GL_RGBA;
	GLenum type = GL_HALF_FLOAT_ARB;

	glGenFramebuffersEXT(1, &sharedFBO);
	for (int i = 0; i < nTexture; i++)
	{
		glGenTextures(1, &textureId[i]);
		glBindTexture(texturetype, textureId[i]);

		glTexImage2D(texturetype, 0, internalformat, res_x, res_y, 0, format, type, 0);
		glTexParameterf(texturetype, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameterf(texturetype, GL_TEXTURE_WRAP_T, GL_CLAMP);
		glTexParameterf(texturetype, GL_TEXTURE_MAG_FILTER, smoothtype);
		glTexParameterf(texturetype, GL_TEXTURE_MIN_FILTER, smoothtype);
	}

	//initialize the textures
	for (int i = 0; i < nTexture; i++)
	{
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sharedFBO);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_EXT, 
			textureId[i], 0);	
		glViewport(0, 0, res_x, res_y);
		glClearColor(0,0,0,0);
		glClear(GL_COLOR_BUFFER_BIT);
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
	}
}

MultiIteratedRenderTexture::~MultiIteratedRenderTexture()
{
	glDeleteFramebuffers(1, &sharedFBO);
	for (int i = 0; i < nTexture; i++)
		glDeleteTextures(1, &textureId[i]);
}

void MultiIteratedRenderTexture::reset()
{
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sharedFBO);
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_EXT, 
		textureId[1], 0);	
	glViewport(0, 0, res_x, res_y);
	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}